package com.my.study.date;

import org.junit.Test;

import java.time.*;
import java.time.chrono.ChronoLocalDate;
import java.time.temporal.ChronoUnit;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAdjuster;
import java.time.temporal.TemporalAdjusters;
import java.util.Date;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.Consumer;

/**
 * @author Carlos
 * @version 1.0
 * @Description Java8 日期API
 *
 * <p>
 *     1、Instant类
 *        对时间轴上的单一瞬间点建模，用于记录应用程序中的事件时间戳，在之后学习的类型转换中，均用此类为中间类完成转换
 *
 *
 *     2、Duration类
 *        表示秒或纳秒时间间隔，适合处理较短时间，需要更高的精确性
 *
 *     3、Period类
 *        表示一段时间的年、月、日
 *
 *     4、LocalDate类
 *        是一个不可变的日期时间对象，表示日期，通常被视为年月日
 *
 *     5、LocalTime类
 *        是一个不可变的日期时间对象，表示时间，通常被视为时分秒
 *
 *     6、LocalDateTime
 *        是LocalDate类和LocalTime类结合体，代表年月日时分秒
 *
 *     7、ZonedDateTime类
 *        具有时区的日期时间的不可变的表示，存储所有日期的时间字段，精确度为纳秒，时区为偏移量，用于处理模糊的本地日期时间
 *
 *
 *
 *
 * </p>
 *
 *
 * <p>
 *     参考博客：https://blog.csdn.net/lianghecai52171314/article/details/105397572
 *
 * </p>
 *
 * @date 2021/8/17 22:54
 **/
public class DateTest {

    @Test
    public void testDate() {

        LocalDate start = LocalDate.of(2021, 3, 2);
        LocalDate end = LocalDate.of(2021, 3, 2);
        System.out.println("start, year = " + start.getYear());
        System.out.println("end, year = " + end.getYear());
        System.out.println("start, month = " + start.getMonthValue());
        System.out.println("end, month = " + end.getMonthValue());



        long between = ChronoUnit.DAYS.between(LocalDate.of(2021, 2, 1), LocalDate.of(2021, 2, 1));
        System.out.println(between);

        long month = ChronoUnit.MONTHS.between(LocalDate.of(2021, 2, 3), LocalDate.of(2021, 4, 4));
        System.out.println(month);

        LocalDate now = LocalDate.now();
        LocalDate dayOfMonth = now.withDayOfMonth(1);


//        Instant

        LocalDateTime localDateTime = DateTimeUtils.todayStart(ZoneId.of(ZoneId.SHORT_IDS.get("CTT")));
        String format = DateTimeUtils.DATE_TIME_FORMAT_MAP.get(DateTimeUtils.DATE_GAP_FORMAT).format(localDateTime);
        System.out.println(format);
        System.out.println(localDateTime);

        LocalDate localDate = LocalDate.now();

    }


    @Test
    public void saleTest() {

        LocalDate payDay = LocalDate.of(2018, 12, 15);

        LocalDate from = LocalDate.from(new PayDayAdjuster().adjustInto(payDay));
        System.out.println(from);

    }


    /**
     * 自定义时间转换器
     *
     * 假如某个公司是在一个月15号发工资，如果发薪日是周某，则调整为上周五
     *
     */
    private static class PayDayAdjuster implements TemporalAdjuster {

        private final int DEFAULT_DAY = 15;

        @Override
        public Temporal adjustInto(Temporal temporal) {
            LocalDate payDay = LocalDate.from(temporal);
            // 改为15号
            LocalDate realPayDay = payDay.withDayOfMonth(DEFAULT_DAY);

            // 如果是周末，改为上周五
            if (realPayDay.getDayOfWeek() == DayOfWeek.SUNDAY || realPayDay.getDayOfWeek() == DayOfWeek.SATURDAY) {
                realPayDay = realPayDay.with(TemporalAdjusters.previous(DayOfWeek.FRIDAY));
            }

            return realPayDay;
        }
    }

    private ExecutorService service = Executors.newCachedThreadPool();

    @Test
    public <T> void testDate1() {
        try {
            MyCallable<T> myCallable = new MyCallable<>(t -> consumerTest(), null);
            service.submit(myCallable);
        } catch (Exception e) {
            System.out.println("testDate1........");
        }
    }

    private <T> void consumerMethod(Consumer<T> consumer, T t) {
        try {
            consumer.accept(t);
        } catch (Exception e) {
            System.out.println("consumerMethod........");
        }
    }

    private void consumerTest() {
        for (int i = 0; i < 10; i++) {
            try {
                int j  = 1 / 0;
            } catch (Exception e) {
                System.out.println("错误" + i + e.getMessage());
            }
        }
    }

    class MyCallable<T> implements Runnable {
        private Consumer<T> consumer;
        private T t;

        public MyCallable(Consumer<T> consumer, T t) {
            this.consumer = consumer;
            this.t = t;
        }

        @Override
        public void run() {
            consumerMethod(consumer, t);
        }
    }

    @Test
    public void testDateIn() {
        System.out.println(LocalDateTime.now());
        LocalDateTime localDateTime = LocalDateTime.now().minusMinutes(35);
        Date date = DateTimeUtils.toDate(localDateTime);
        System.out.println(date);
    }

    /**
     * 计算日期间隔
     */
    @Test
    public void dateIntervalTest() {
        LocalDate start = LocalDate.of(2021, 2, 3);
        LocalDate end = LocalDate.of(2022, 4, 3);
        int startDay = start.getDayOfMonth();
        int endDay = end.getDayOfMonth();
        System.out.println("start, year = " + start.getYear());
        System.out.println("end, year = " + end.getYear());
        System.out.println("start, month = " + start.getMonthValue());
        System.out.println("end, month = " + end.getMonthValue());
        System.out.println("start, day = " + startDay);
        System.out.println("end, day = " + endDay);

        long month = ChronoUnit.MONTHS.between(start, end);
        month = startDay <= endDay ? month + 1 : month + 2;

        System.out.println(month);

    }

}
